#ifndef SDLENGINE_TOOL_HPP
#define SDLENGINE_TOOL_HPP

#include <memory>
#include <random>
#include <functional>
#include <type_traits>

namespace sdl_engine {

template <typename T>
using Unique = std::unique_ptr<T>;

template <typename T>
using Ref = std::shared_ptr<T>;

/* @brief linear travers innermost element in container( for vector and list or their mixture)
 * @WARNING not support array yet. */

template <typename U, typename T>
void LinearForeach(T& elem, std::function<void(U&)> func) {
    func(elem);
}

template <typename U,
          typename T,
          template<typename = T,
                   typename = std::allocator<T>>
          class Cont>
void LinearForeach(Cont<T>& cont, std::function<void(U&)> func) {
    for (T& elem: cont)
        LinearForeach(elem, func);
}

template <typename T1, typename T2>
bool _feq(const T1& a, const T2& b) {
    return abs(a - b) <= std::numeric_limits<std::common_type_t<T1, T2>>::epsilon();
}

int Fps();

template <typename T>
T Random(const T& low, const T& high) {
    static_assert(std::is_floating_point_v<T> || std::is_integral_v<T>);

    std::random_device device;
    if constexpr (std::is_floating_point_v<T>) {
        std::uniform_real_distribution<T> dist(low, high);
        return dist(device);
    } else {
        std::uniform_int_distribution<T> dist(low, high);
        return dist(device);
    }
}

}

#endif
